#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <jsoncpp/json/json.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "Util.hpp"

// #define MYSELF 1

namespace Protocal_ns
{
#define SEP " "
#define SEP_LEN strlen(SEP)
#define HEADER_SEP "\r\n"
#define HEADER_SEP_LEN strlen(HEADER_SEP)
    // 二者都要提供序列化和反序列化的功能
    std::string AddHeader(std::string &str)
    {
        // std::cout << "AddHeader 之前:\n"
        //           << str << std::endl;

        std::string s = std::to_string(str.size());
        s += HEADER_SEP;
        s += str;
        s += HEADER_SEP;

        // std::cout << "AddHeader 之后:\n"
        //           << s << std::endl;

        return s;
    }

    std::string RemoveHeader(const std::string &str, int len)
    {
        return str.substr(str.size() - HEADER_SEP_LEN - len, len);
    }

    int ReadPackage(std::string &inbuffer, std::string *package)
    {
        std::cout << "ReadPackage inbuffer 之前:\n"
                  << inbuffer << std::endl;
        // 分析
        auto pos = inbuffer.find(HEADER_SEP);
        if (pos == inbuffer.npos)
            return 0;

        // 获取头部字符串
        std::string lenstr = inbuffer.substr(0, pos);
        int len = Util::toInt(lenstr);

        // 整个报文的长度
        int packagelen = lenstr.size() + len + 2 * HEADER_SEP_LEN;
        if (inbuffer.size() < packagelen)
            return 0;

        // 获取整个报文
        *package = inbuffer.substr(0, packagelen);

        // 从缓冲区中删除掉已读的数据
        inbuffer.erase(0, packagelen);

        std::cout << "ReadPackage inbuffer 之后:\n"
                  << inbuffer << std::endl;

        return len;
    }

    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char op) : _x(x), _y(y), _op(op)
        {
        }
        ~Request()
        {
        }

        bool Serialize(std::string *outstr)
        {
            *outstr = "";
#ifdef MYSELF
            std::string x_string = std::to_string(_x);
            std::string y_string = std::to_string(_y);
            *outstr = x_string + SEP + _op + SEP + y_string;
#else
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;
            Json::FastWriter writer;
            *outstr = writer.write(root);
#endif
            return true;
        }

        bool DeSerialize(const std::string &instr)
        {
#ifdef MYSELF
            std::vector<std::string> result;
            Util::StringSplit(instr, SEP, &result);
            if (result.size() != 3)
                return false;
            if (result[1].size() != 1)
                return false;
            _x = Util::toInt(result[0]);
            _op = result[1][0];
            _y = Util::toInt(result[2]);
#else
            Json::Value root;
            Json::Reader reader; // 反序列化
            reader.parse(instr, root);

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt();

#endif
            return true;
        }

        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response()
        {
        }
        Response(int result, int code) : _result(result), _code(code)
        {
        }
        ~Response()
        {
        }

        bool Serialize(std::string *outstr)
        {
            *outstr = "";
#ifdef MYSELF
            std::string res_string = to_string(_result);
            std::string code_string = to_string(_code);
            *outstr = res_string + SEP + code_string;
            return true;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            *outstr = writer.write(root);
#endif
        }

        bool DeSerialize(const std::string &instr)
        {
#ifdef MYSELF

            std::vector<std::string> result;
            Util::StringSplit(instr, SEP, &result);
            if (result.size() != 2)
                return false;

            _result = Util::toInt(result[0]);
            _code = Util::toInt(result[1]);
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(instr, root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();
#endif
        }
        int _result;
        int _code; // 错误码
    };
}
